#!/usr/bin/perl

package Swignition::Export::Address;
use Swignition::Export;
use JSON 2.0;

# Reference:
# http://www.ibiblio.org/hhalpin/homepage/notes/vcardtable.html
# (Though that page does contain a number of mistakes, such as equating a vCard
# "TITLE" [a job title] with a FOAF "title" [e.g. Mr, Mrs].)

sub is
{
	my $subject = shift;
	return unless ($subject);
	return unless (ref $subject eq 'Swignition::RDFModel::Subject');	
	return
		unless (defined $subject->property('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'));
	foreach my $Type ( @{$subject
		->property('http://www.w3.org/1999/02/22-rdf-syntax-ns#type')
		->valObjects} )
	{
		my $type = $Type->toString;
		return 1
			if (($type eq 'http://www.w3.org/2001/vcard-rdf/3.0#ADR')
			||  ($type eq 'http://www.w3.org/2006/vcard/ns#Address')
			||  ($type eq 'http://www.w3.org/2000/10/swap/pim/contact#Address')
			||  ($type eq 'urn:ietf:rfc:2426#Adr'));
	}
	return;
}

sub outputs
{
	return [
		{
			code => 'VCFLine',
			name => 'vCard-compatible Line',
			type => 'text/x-directory-part'
		},
		{
			code => 'Text',
			name => 'Plain text address (one line)',
			type => 'text/plain'
		},
		{
			code  => 'JSON',
			name  => 'jCard adr',
			type  => 'text/x-json',
			multi => 1
		}
	];
}

sub multiJSON
{
	my $triples = shift;
	my @rv;
	foreach my $s (keys %$triples)
	{
		if (defined $triples->{$s} && is($triples->{$s}))
		{
			my %r = _outJSON($triples, $s);
			push @rv, \%r;
		}
	}
 	return to_json(\@rv, {utf8 => 1, pretty => 1, canonical => 1})."\n";
}


sub outJSON
{
	my %json = _outJSON(@_);
 	return to_json(\%json, {utf8 => 1, pretty => 1, canonical => 1})."\n";
}

sub _outJSON
{
	my $triples = shift;
	my $subject = shift;
	my $S = findSubject($triples, $subject);
	my %adr;

	# Basics
	$adr{'post-office-box'} = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#post-office-box',
		'http://www.w3.org/2006/vcard/ns#post-office-box',
		'http://www.w3.org/2001/vcard-rdf/3.0#Pobox'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$adr{'extended-address'} = [allOfLiteral($S,  
		['urn:ietf:rfc:2426#extended-address',
		'http://www.w3.org/2006/vcard/ns#extended-address',
		'http://www.w3.org/2001/vcard-rdf/3.0#Extadd',
		'http://www.w3.org/2000/10/swap/pim/contact#addressProperty'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$adr{'street-address'} = [allOfLiteral($S,  
		['urn:ietf:rfc:2426#street-address',
		'http://www.w3.org/2006/vcard/ns#street-address',
		'http://www.w3.org/2001/vcard-rdf/3.0#Street',
		'http://www.w3.org/2000/10/swap/pim/contact#street'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$adr{'locality'} = [allOfLiteral($S,  
		['urn:ietf:rfc:2426#locality',
		'http://www.w3.org/2006/vcard/ns#locality',
		'http://www.w3.org/2001/vcard-rdf/3.0#Locality',
		'http://www.w3.org/2000/10/swap/pim/contact#city'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$adr{'region'} = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#region',
		'http://www.w3.org/2006/vcard/ns#region',
		'http://www.w3.org/2001/vcard-rdf/3.0#Region',
		'http://www.w3.org/2000/10/swap/pim/contact#stateOrProvince'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$adr{'postal-code'} = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#postal-code',
		'http://www.w3.org/2006/vcard/ns#postal-code',
		'http://www.w3.org/2001/vcard-rdf/3.0#Pcode',
		'http://www.w3.org/2000/10/swap/pim/contact#postalCode',
		'http://www.w3.org/2000/10/swap/pim/contact#zip'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$adr{'country-name'} = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#country-name',
		'http://www.w3.org/2006/vcard/ns#country-name',
		'http://www.w3.org/2001/vcard-rdf/3.0#Country',
		'http://www.w3.org/2000/10/swap/pim/contact#country'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$adr{'type'} = [allOfLiteral($S,  
		['urn:ietf:rfc:2426#type',
		'http://buzzword.org.uk/rdf/vcardx#usage',
		'http://www.w3.org/2006/vcard/ns#type',
		'http://www.w3.org/2001/vcard-rdf/3.0#ADRPROPERTIES'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	
	# Default Types
	unless (scalar(@{$adr{type}}))
	{
		@defaults = qw(postal parcel work);
		push @defaults, 'intl' if (scalar(@{$adr{'country-name'}}));
		$adr{type} = \@defaults;
	}

	# Geo
	my @geos = allOfLiteral($S, 
		['urn:ietf:rfc:2426#geo',
		'http://www.w3.org/2006/vcard/ns#geo',
		'http://www.w3.org/2001/vcard-rdf/3.0#GEO'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value']);
	foreach my $geo (@geos)
	{
		my $Geo = findSubject($triples, $geo);
		if ($Geo && Swignition::Export::Point::is($Geo->uri))
		{
			my %g = Swignition::Export::Point::_outJSON($triples, $Geo->uri);
			push @{$adr{'geo'}}, \%g;
		}
	}

	# Remove empty leafnodes from structure.	
	foreach $k (keys %adr)
	{
		if (!defined $adr{$k})
			{ delete $adr{$k}; }
		elsif ((ref $adr{$k}) eq 'ARRAY')
			{ delete $adr{$k} unless scalar(@{$adr{$k}}); }
	}
	
	return %adr;
}

sub outText
{
	my ($key, $adr) = outVCFLine(@_);
	
	$adr =~ s/\;/\, /g;
	$adr =~ s/\\\,/\,/g;
	while ($adr =~ /\, \,/)
		{ $adr =~ s/\, \,/\,/g; }
	$adr =~ s/(^(\, )+|(\, )+$)//g;
	
	return $adr;
}

sub outVCFLine
{
	my $triples = shift;
	my $subject = shift;
	my $S = $triples->{$subject};

	my @addr;
	$addr[0] = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#post-office-box',
		'http://www.w3.org/2006/vcard/ns#post-office-box',
		'http://www.w3.org/2001/vcard-rdf/3.0#Pobox'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$addr[1] = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#extended-address',
		'http://www.w3.org/2006/vcard/ns#extended-address',
		'http://www.w3.org/2001/vcard-rdf/3.0#Extadd',
		'http://www.w3.org/2000/10/swap/pim/contact#addressProperty'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$addr[2] = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#street-address',
		'http://www.w3.org/2006/vcard/ns#street-address',
		'http://www.w3.org/2001/vcard-rdf/3.0#street-address',
		'http://www.w3.org/2000/10/swap/pim/contact#Street'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$addr[3] = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#locality',
		'http://www.w3.org/2006/vcard/ns#locality',
		'http://www.w3.org/2001/vcard-rdf/3.0#Locality',
		'http://www.w3.org/2000/10/swap/pim/contact#city'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$addr[4] = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#region',
		'http://www.w3.org/2006/vcard/ns#region',
		'http://www.w3.org/2001/vcard-rdf/3.0#Region'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$addr[5] = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#postal-code',
		'http://www.w3.org/2006/vcard/ns#postal-code',
		'http://www.w3.org/2001/vcard-rdf/3.0#Pcode'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
	$addr[6] = [allOfLiteral($S, 
		['urn:ietf:rfc:2426#country-name',
		'http://www.w3.org/2006/vcard/ns#country-name',
		'http://www.w3.org/2001/vcard-rdf/3.0#Country',
		'http://www.w3.org/2000/10/swap/pim/contact#country'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value'])];
		
	my @address;
	foreach my $A (@addr)
	{
		my @line;
		foreach my $a (@$A)
		{
			$a =~ s/\,/\\\,/g;
			$a =~ s/\;/\\\;/g;
			push @line, $a;
		}
		
		push @address, (join ', ', @line);
	}
	my $address = join ';', @address;
		
	@types = allOfLiteral($S, 
		['urn:ietf:rfc:2426#type',
		'http://buzzword.org.uk/rdf/vcardx#usage',
		'http://www.w3.org/2001/vcard-rdf/3.0#ADRPROPERTIES'],
		['urn:ietf:rfc:2426#value',
		'http://www.w3.org/1999/02/22-rdf-syntax-ns#value']);
	my $types;
	foreach my $t (@types)
	{
		$t =~ s/(^\s+|\s+$)//g;
		$t =~ s/\s+/-/g;
		$types .= ",".uc($t);
	}
	$types =~ s/^\,//;
	
	$key = 'ADR';
	$key = "ADR;TYPE=$types"
		if (length $types);
		
	return ($key, $address);
}

1;
